package org.examples;

import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Map;

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.entity.mime.StringBody;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.message.StatusLine;
import org.synchronoss.cloud.nio.multipart.Multipart;
import org.synchronoss.cloud.nio.multipart.MultipartContext;
import org.synchronoss.cloud.nio.multipart.NioMultipartParser;
import org.synchronoss.cloud.nio.multipart.NioMultipartParserListener;
import org.synchronoss.cloud.nio.stream.storage.StreamStorage;

import lombok.extern.slf4j.Slf4j;

import static org.examples.DebugConstants.fullSchema;
import static org.examples.DebugConstants.host;
import static org.examples.DebugConstants.vocsInputJson;
import static org.examples.DebugConstants.vocsParametersJson;
import static org.examples.DebugConstants.vocsPath;

@Slf4j
public class VocsClassicNioMultipart {

  public static void main(final String[] args) throws Exception {

    final HttpHost target = new HttpHost(host);
    try (final CloseableHttpClient httpclient = HttpClients.createDefault()) {
      final HttpPost httppost = new HttpPost(fullSchema() + host + vocsPath());

      final StringBody inputBody = new StringBody(vocsInputJson, ContentType.APPLICATION_JSON);
      final StringBody parametersBody = new StringBody(vocsParametersJson, ContentType.APPLICATION_JSON);

      final HttpEntity reqEntity = MultipartEntityBuilder.create()
          .addPart("Input", inputBody)
          .addPart("Parameters", parametersBody)
          .build();

      httppost.setEntity(reqEntity);
      System.out.println("executing request " + httppost);
      httpclient.execute(httppost, response -> {

        System.out.println("----------------------------------------");
        System.out.println(httppost + "->" + new StatusLine(response));
        final HttpEntity resEntity = response.getEntity();
        InputStream is = resEntity.getContent();
        //        is.read();
        //        is.read();
        Path audioPath = Paths.get("audio.opus");
        audioPath.toFile().createNewFile();
        MultipartContext context = new MultipartContext("multipart/form-data; boundary=Nuance_VoCS_0", -1, "ISO-8859-1");
        NioMultipartParserListener listener = new NioMultipartParserListener() {

          @Override
          public void onPartFinished(final StreamStorage partBodyStreamStorage, final Map<String, List<String>> headersFromPart) {
            log.info("onPartFinished");
            headersFromPart.forEach((x, y) -> {
              log.info(x);
              for (String s : y) {
                log.info(s);
              }
            });
            // The parser completed parsing the part.
            // The parsed headers are available in the headersFromPart map
            // The part body can be read from the partBodyStreamStorage which provides an InputStream
          }

          @Override
          public void onNestedPartStarted(final Map<String, List<String>> headersFromParentPart) {
            // The parser identified that the current part contains a nested multipart body
            // The headers are provided in the headersFromParentPart
            // Like for the level 0 parts, the parser will notify the sub parts completion via the methods onPartFinished(...) and onFormFieldPartFinished(...)
            // When the nested multipart body is finished, the parser will call onNestedPartFinished()
          }

          @Override
          public void onNestedPartFinished() {
            // Called when a nested multipart body has been parsed
          }

          @Override
          public void onAllPartsFinished() {
            // Called when the multipart processing finished (encountered the close boundary). No more parts are available!
          }

          @Override
          public void onError(String message, Throwable cause) {
            // An error happened during the parsing.
            // At this point the parser is in an error state and it cannot process any data anymore.
          }
        };
        NioMultipartParser parser = Multipart.multipart(context).forNIO(listener);
        int bytesRead;
        byte bytes[] = new byte[1024];
        while ((bytesRead = is.read(bytes)) != -1) {
          // Pass the received bytes into the parser.
          // When something is ready the listener will be called!
          parser.write(bytes, 0, bytesRead);
        }

        //        String text = EntityUtils.toString(response.getEntity());
        //        System.out.println(text);
        return null;
      });
    }
  }
}
